/* dprintf.c -- a very minimal printf
**
** Copyright 2006, Brian Swetland.  All rights reserved.
** See provided LICENSE file or http://frotz.net/LICENSE for details.
*/

#include <stdarg.h>
#include "devices.h"

/* cheap and crappy printf for debugging. it knows about:
**
** d - signed integer
** u - unsigned integer
** x,p - unsigned hex
** c - character
** s - string
** b - byte (2 digits hex)
** w - word (8 digits hex)
**
*/

static char bin2hex[16] = {
    '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
};

void dprintf(const char *fmt, ...)
{
    va_list ap;
    unsigned u;
    int i;
    char *x;
    char tmp[12];
    tmp[11] = 0;

    va_start(ap, fmt);
    while((u = *fmt++) != 0) {
        if(u == '%') {
            switch(u = *fmt++) {
            case 0:
                goto done;
                
            case 'd':
                i = va_arg(ap, int);
                if(i < 0) {
                    /* BUG for -MAXINT */
                    u = -i; 
                    ser_putc('-');
                } else {
                    u = i;
                }
                goto variable_dec_out;
                
            case 'u':
                u = va_arg(ap, unsigned);
            variable_dec_out:
                x = tmp+11;
                do {
                    *--x = '0' + (u % 10);
                    u /= 10;
                } while(u != 0);
                ser_puts(x);
                continue;
                
            case 'c':
                u = va_arg(ap, unsigned);
                ser_putc(u);
                continue;
                
            case 'b':
                i = 2;
                goto fixed_hex_out;

            case 'h':
                i = 4;
                goto fixed_hex_out;

            case 'x':
                i = 8;
            fixed_hex_out:
                u = va_arg(ap, unsigned);
                x = tmp+11;
                while(i-- > 0) {
                    *--x = bin2hex[u & 15];
                    u >>= 4;
                }
                ser_puts(x);
                continue;
                
            case 's':
                x = va_arg(ap, char*);
                ser_puts(x);
                continue;
                
            default:
                ser_putc('%');
                break;
            }
        }            
        ser_putc(u);
    }
done:
    va_end(ap);
}
